using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace O3L
{
	public class HiResTimer
	{
		private bool isUsingQPF;
		private bool isTimerStopped;
		private long ticksPerSecond;
		private long stopTime;
		private long lastElapsedTime;
		private long baseTime;
		private double m_TotalTime;
		private float m_FramesPerSecond;
		private float m_FrameCounter;
        private double m_ElapsedTime;


        public float FramesPerSecond
        {
            get{return m_FramesPerSecond;}
        }
        public double ElapsedTime
        {
            get{return m_ElapsedTime;}
        }    
		
		public HiResTimer()
		{
			isTimerStopped = true;
			ticksPerSecond = 0;
			stopTime = 0;
			lastElapsedTime = 0;
			baseTime = 0;
			// Use QueryPerformanceFrequency to get frequency of the timer
			isUsingQPF = QueryPerformanceFrequency(ref ticksPerSecond);
		}

		/// <summary>
		/// Resets the timer
		/// </summary>
		public void Reset()
		{
			if (!isUsingQPF)
				return; // Nothing to do

			// Get either the current time or the stop time
			long time = 0;
			if (stopTime != 0)
				time = stopTime;
			else
				QueryPerformanceCounter(ref time);

			baseTime = time;
			lastElapsedTime = time;
			stopTime = 0;
			isTimerStopped = false;
		}

		/// <summary>
		/// Starts the timer
		/// </summary>
		public void Start()
		{
			if (!isUsingQPF)
				return; // Nothing to do

			// Get either the current time or the stop time
			long time = 0;
			if (stopTime != 0)
				time = stopTime;
			else
				QueryPerformanceCounter(ref time);

			if (isTimerStopped)
				baseTime += (time - stopTime);
			stopTime = 0;
			lastElapsedTime = time;
			isTimerStopped = false;
		}

		/// <summary>
		/// Stop (or pause) the timer
		/// </summary>
		public void Stop()
		{
			if (!isUsingQPF)
				return; // Nothing to do

			if (!isTimerStopped)
			{
				// Get either the current time or the stop time
				long time = 0;
				if (stopTime != 0)
					time = stopTime;
				else
					QueryPerformanceCounter(ref time);

				stopTime = time;
				lastElapsedTime = time;
				isTimerStopped = true;
			}
		}

		/// <summary>
		/// Advance the timer a tenth of a second
		/// </summary>
		public void Advance()
		{
			if (!isUsingQPF)
				return; // Nothing to do

			stopTime += ticksPerSecond / 10;
		}

		/// <summary>
		/// Get the absolute system time
		/// </summary>
		public double GetAbsoluteTime()
		{
			if (!isUsingQPF)
				return -1.0; // Nothing to do

			// Get either the current time or the stop time
			long time = 0;
			if (stopTime != 0)
				time = stopTime;
			else
				QueryPerformanceCounter(ref time);

			double absolueTime = time / (double)ticksPerSecond;
			return absolueTime;
		}

		/// <summary>
		/// Get the current time
		/// </summary>
		public double GetTime()
		{
			if (!isUsingQPF)
				return -1.0; // Nothing to do

			// Get either the current time or the stop time
			long time = 0;
			if (stopTime != 0)
				time = stopTime;
			else
				QueryPerformanceCounter(ref time);

			double appTime = (double)(time - baseTime) / (double)ticksPerSecond;
			return appTime;
		}

		/// <summary>
		/// get the time that elapsed between GetElapsedTime() calls
		/// </summary>
		public double GetElapsedTime()
		{
			if (!isUsingQPF)
				return -1.0; // Nothing to do

			// Get either the current time or the stop time
			long time = 0;
			if (stopTime != 0)
				time = stopTime;
			else
				QueryPerformanceCounter(ref time);

			m_ElapsedTime = (double)(time - lastElapsedTime) / (double)ticksPerSecond;
			lastElapsedTime = time;
			m_TotalTime += m_ElapsedTime;
			return m_ElapsedTime;
		}

		public float CalculateFPS()
		{
			if (m_TotalTime >= 1.0f){
				m_FramesPerSecond = m_FrameCounter;
				m_FrameCounter = 0;
				m_TotalTime = 0.0f;
			}

			m_FrameCounter++;
			return m_FramesPerSecond;

		}

		/// <summary>
		/// Returns true if timer stopped
		/// </summary>
		public bool IsStopped
		{
			get { return isTimerStopped; }
		}

		


		[System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
		[DllImport("kernel32")]
		public static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);

		[System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
		[DllImport("kernel32")]
		public static extern bool QueryPerformanceCounter(ref long PerformanceCount);
	}
}
